package com.nhancv.kurentoandroid.one2one;

import android.Manifest;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.os.Build;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;

import com.hannesdorfmann.mosby.mvp.MvpActivity;
import com.nhancv.kurentoandroid.R;
import com.nhancv.npermission.NPermission;
import com.nhancv.webrtcpeer.rtc_plugins.ProxyRenderer;

import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Click;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.ViewById;
import org.webrtc.Camera1Enumerator;
import org.webrtc.Camera2Enumerator;
import org.webrtc.CameraEnumerator;
import org.webrtc.CameraVideoCapturer;
import org.webrtc.EglBase;
import org.webrtc.Logging;
import org.webrtc.RendererCommon;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoRenderer;

import static com.nhancv.kurentoandroid.bottom_navigation.HomeFragment.tocounter;
import static com.nhancv.kurentoandroid.loginActivity.playerid;

@EActivity(R.layout.activity_one2one)
public class One2OneActivity extends MvpActivity<One2OneView, One2OnePresenter>
        implements One2OneView, NPermission.OnPermissionResult, SensorEventListener {

    private static final String TAG = One2OneActivity.class.getSimpleName();

    @ViewById(R.id.llInputRegister)
    protected LinearLayout llInputRegister;
    @ViewById(R.id.etInputName)
    protected EditText etInputName;
    @ViewById(R.id.etInputPeer)
    protected EditText etInputPeer;
    @ViewById(R.id.btRegister)
    protected Button btRegister;
    @ViewById(R.id.btOne2OneCall)
    protected Button btOne2OneCall;

    @ViewById(R.id.vGLSurfaceViewCallFull)
    protected SurfaceViewRenderer vGLSurfaceViewCallFull;
    @ViewById(R.id.vGLSurfaceViewCallPip)
    protected SurfaceViewRenderer vGLSurfaceViewCallPip;

    private NPermission nPermission;
    private EglBase rootEglBase;
    private ProxyRenderer localProxyRenderer;
    private ProxyRenderer remoteProxyRenderer;
    private Toast logToast;
    private boolean isGranted;
    private boolean isSwappedFeeds;
    boolean flag = false;

    //定义传感器
    private SensorManager sManager;
    //加速度传感器数据
    private final float[] accelerometerReading = new float[3];
    //地磁传感器数据
    private final float[] magnetometerReading = new float[3];
    //旋转矩阵，用来保存磁场和加速度的数据
    private final float[] rotationMatrix = new float[9];
    //方向数据
    private final float[] orientationAngles = new float[3];
    //public CameraVideoCapturer videoCapturer;

    @AfterViews
    protected void init() {

        sManager = (SensorManager) getSystemService(SENSOR_SERVICE);

        if(!TextUtils.isEmpty(playerid)){
            etInputName.setText(playerid);
        }
        if(!TextUtils.isEmpty(tocounter)){
            etInputPeer.setText(tocounter);
        }
        Button button =  findViewById(R.id.btntest);
        button.setOnClickListener(view -> {
            flag = !flag;
            if(!flag){
                vGLSurfaceViewCallFull.setRotationX(0);
                vGLSurfaceViewCallFull.setRotationY(0);
            }
        });
        /*
        Button button2 =  findViewById(R.id.btntest2);
        button2.setOnClickListener(view -> {
            videoCapturer.switchCamera(null);
        });
        */
        nPermission = new NPermission(true);

        setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);


        //config peer
        localProxyRenderer = new ProxyRenderer();
        remoteProxyRenderer = new ProxyRenderer();
        rootEglBase = EglBase.create();

        vGLSurfaceViewCallFull.init(rootEglBase.getEglBaseContext(), null);
        vGLSurfaceViewCallFull.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
        vGLSurfaceViewCallFull.setEnableHardwareScaler(true);
        vGLSurfaceViewCallFull.setMirror(true);

        vGLSurfaceViewCallPip.init(rootEglBase.getEglBaseContext(), null);
        vGLSurfaceViewCallPip.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
        vGLSurfaceViewCallPip.setEnableHardwareScaler(true);
        vGLSurfaceViewCallPip.setMirror(true);
        vGLSurfaceViewCallPip.setZOrderMediaOverlay(true);

        // Swap feeds on pip view click.
        vGLSurfaceViewCallPip.setOnClickListener(view -> setSwappedFeeds(!isSwappedFeeds));

        setSwappedFeeds(true);
        presenter.connectServer();
    }

    @Override
    public void setSwappedFeeds(boolean isSwappedFeeds) {
        Logging.d(TAG, "setSwappedFeeds: " + isSwappedFeeds);
        this.isSwappedFeeds = isSwappedFeeds;
        localProxyRenderer.setTarget(isSwappedFeeds ? vGLSurfaceViewCallFull : vGLSurfaceViewCallPip);
        remoteProxyRenderer.setTarget(isSwappedFeeds ? vGLSurfaceViewCallPip : vGLSurfaceViewCallFull);
        vGLSurfaceViewCallFull.setMirror(isSwappedFeeds);
        vGLSurfaceViewCallPip.setMirror(!isSwappedFeeds);
    }

    @Override
    public void socketConnect(boolean success) {
        llInputRegister.setVisibility(success ? View.VISIBLE : View.GONE);
    }



    @Override
    public void disconnect() {
        localProxyRenderer.setTarget(null);
        if (vGLSurfaceViewCallFull != null) {
            vGLSurfaceViewCallFull.release();
            vGLSurfaceViewCallFull = null;
        }

        finish();
    }

    @Override
    public void onResume() {
        super.onResume();

        btRegister.setEnabled(true);
        btOne2OneCall.setEnabled(false);

        //注册加速度传感器监听
        Sensor acceleSensor = sManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        sManager.registerListener(this, acceleSensor, SensorManager.SENSOR_DELAY_NORMAL);
        //注册磁场传感器监听
        Sensor magSensor = sManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        sManager.registerListener(this, magSensor, SensorManager.SENSOR_DELAY_NORMAL);

    }

    public void startCall() {
        if (Build.VERSION.SDK_INT < 23 || isGranted) {
            presenter.startCall();
        } else {
            nPermission.requestPermission(this, Manifest.permission.CAMERA);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        nPermission.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    @Override
    public void onPermissionResult(String permission, boolean isGranted) {
        switch (permission) {
            case Manifest.permission.CAMERA:
                this.isGranted = isGranted;
                if (!isGranted) {
                    nPermission.requestPermission(this, Manifest.permission.CAMERA);
                } else {
                    //nPermission.requestPermission(this, Manifest.permission.RECORD_AUDIO);

                    presenter.startCall();

                }
                break;
            default:
                break;
        }
    }

    @NonNull
    @Override
    public One2OnePresenter createPresenter() {
        return new One2OnePresenter(getApplication());
    }


    @Click(R.id.btRegister)
    protected void btRegisterClick() {
        if (!TextUtils.isEmpty(etInputName.getText().toString())) {
            presenter.register(etInputName.getText().toString());
        }

    }

    @Click(R.id.btOne2OneCall)
    protected void btOne2OneClick() {
        if (!TextUtils.isEmpty(etInputPeer.getText().toString())) {
            transactionToCalling(etInputName.getText().toString(), etInputPeer.getText().toString(), true);
        }
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        presenter.disconnect();
    }

    @Override
    public void logAndToast(String msg) {
        Log.d(TAG, msg);
        if (logToast != null) {
            logToast.cancel();
        }
        logToast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
        logToast.show();
    }

    @Override
    public CameraVideoCapturer createVideoCapturer() {
        CameraVideoCapturer videoCapturer;
        if (useCamera2()) {
            if (!captureToTexture()) {
                return null;
            }
            videoCapturer = createCameraCapturer(new Camera2Enumerator(this));
        } else {
            videoCapturer = createCameraCapturer(new Camera1Enumerator(captureToTexture()));
        }
        if (videoCapturer == null) {
            return null;
        }
        return videoCapturer;
    }

    @Override
    public EglBase.Context getEglBaseContext() {
        return rootEglBase.getEglBaseContext();
    }

    @Override
    public VideoRenderer.Callbacks getLocalProxyRenderer() {
        return localProxyRenderer;
    }

    @Override
    public VideoRenderer.Callbacks getRemoteProxyRenderer() {
        return remoteProxyRenderer;
    }

    @Override
    public void registerStatus(boolean success) {
        btRegister.setEnabled(!success);
        btOne2OneCall.setEnabled(success);
    }

    @Override
    public void transactionToCalling(String fromPeer, String toPeer, boolean isHost) {
        presenter.initPeerConfig(fromPeer, toPeer, isHost);
        startCall();
    }

    @Override
    public void incomingCalling(String fromPeer) {
        transactionToCalling(fromPeer, etInputName.getText().toString(), false);
    }

    @Override
    public void stopCalling() {
        llInputRegister.setVisibility(View.VISIBLE);
    }

    @Override
    public void startCallIng() {
        llInputRegister.setVisibility(View.GONE);
    }

    private boolean useCamera2() {
        return Camera2Enumerator.isSupported(this) && presenter.getDefaultConfig().isUseCamera2();
    }

    private boolean captureToTexture() {
        return presenter.getDefaultConfig().isCaptureToTexture();
    }

    private CameraVideoCapturer createCameraCapturer(CameraEnumerator enumerator) {
        final String[] deviceNames = enumerator.getDeviceNames();
        // First, try to find front facing camera
        for (String deviceName : deviceNames) {
            if (enumerator.isFrontFacing(deviceName)) {
                CameraVideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);

                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }

        // Front facing camera not found, try something else
        for (String deviceName : deviceNames) {
            if (!enumerator.isFrontFacing(deviceName)) {
                CameraVideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);

                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }

        return null;
    }
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        //判断sensor类型

        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            System.arraycopy(event.values, 0, accelerometerReading,
                    0, accelerometerReading.length);
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            System.arraycopy(event.values, 0, magnetometerReading,
                    0, magnetometerReading.length);
        }
        if(flag) {
            updateOrientationAngles();
        }
    }


    public double changeData(float input) {
        double stackNum = ((360f+input*180f/Math.PI)%360);
        if(stackNum>180){
            stackNum = stackNum-360;
        }
        return stackNum;
    }

    public void updateOrientationAngles() {
        SensorManager.getRotationMatrix(rotationMatrix, null,
                accelerometerReading, magnetometerReading);

        //根据旋转矩阵计算设备的方向
        //参数1：旋转数组
        //参数2：模拟方向传感器的数据
        SensorManager.getOrientation(rotationMatrix, orientationAngles);

        double RY = changeData(orientationAngles[2]);
        double RX = changeData(orientationAngles[1]);
        if(RX<45 && RX>-45){
            vGLSurfaceViewCallFull.setRotationX(-(float)RX);
        }
        else{
            vGLSurfaceViewCallFull.setRotationX(0);
        }

        if(RY<45 && RY>-45){
            vGLSurfaceViewCallFull.setRotationY(-(float)RY);
        }
        else{
            vGLSurfaceViewCallFull.setRotationY(0);
        }

    }

}

